package com.wengen.mvc.servlet;

import com.wengen.mvc.annotation.*;
import com.wengen.mvc.controller.WengenController;
import com.wengen.mvc.service.WengenService;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Auther: 朱稳根
 * @Date: 2018/8/25 23:23
 * @Description:
 */
public class DispatcherServlet extends HttpServlet {

    //存放所有类路径
    List<String> classNames = new ArrayList<String>();
    //存放所有实例化的类
    Map<String, Object> beans = new HashMap<String, Object>();
    //存放请求地址路径
    Map<String, Object> handerMap = new HashMap<String, Object>();


    @Override
    public void init(ServletConfig config) throws ServletException {
        //扫描所有的bean
        doScanClass("com.wengen");//根目录
        //根据扫描到的list结果，生成对象(反射对象)
        doInstance();
        //注入依赖关系
        doAutowired();
        //建立地址关系
        urlMapping();
    }
    public void urlMapping(){
        for (Map.Entry<String, Object> entry : beans.entrySet()) {
            //差点坑死
            Object instance = entry.getValue();
            Class<?> clazz = instance.getClass();
            if (clazz.isAnnotationPresent(WenController.class)) {
                WenRequestMapping mapping = clazz.getAnnotation(WenRequestMapping.class);
                String classPath = mapping.value();//wengen
                Method[] methods = clazz.getMethods();//获取类里的所有方法
                for (Method method : methods) {
                    if (method.isAnnotationPresent(WenRequestMapping.class)) {
                        WenRequestMapping mapping1 = method.getAnnotation(WenRequestMapping.class);
                        String methodPath = mapping1.value();
                        handerMap.put(classPath + methodPath, method);//key=wengen/getWengen value=getWengen
                    }else{
                        continue;
                    }
                }

            }else{
                continue;
            }
        }
    }

    public void doAutowired() {
        for (Map.Entry<String, Object> entry : beans.entrySet()) {
            //差点坑死
            Object instance = entry.getValue();
            Class<?> clazz = instance.getClass();
            if (clazz.isAnnotationPresent(WenController.class)) {
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    if (field.isAnnotationPresent(WenAutowired.class)) {
                        WenAutowired autowired = field.getAnnotation(WenAutowired.class);
                        String key = autowired.value();
                        field.setAccessible(true);//成员变量私有权限打开
                        try {
                            //完成值的注入，
                            field.set(instance, beans.get(key));
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }

                    }else{
                        continue;
                    }
                }
            }else{
                continue;
            }
        }
    }

    public void doInstance() {
        for (String className : classNames) {
            //去掉后缀名得到全限路径：com.wengen.mvc.controller.WengenController
            String cn = className.replace(".class", "");
            try {
                Class<?> clazz = Class.forName(cn);

                if(clazz.isAnnotationPresent(WenController.class)){
                    //扫描到的是控制类
                    Object instance = clazz.newInstance();
                    WenRequestMapping mapping = clazz.getAnnotation(WenRequestMapping.class);
                    String key = mapping.value();
                    beans.put(key, instance);
                }else if(clazz.isAnnotationPresent(WenService.class)){
                    //得到的是一个服务类
                    Object instance = clazz.newInstance();
                    WenService service = clazz.getAnnotation(WenService.class);
                    String key = service.value();
                    beans.put(key, instance);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

    public void doScanClass(String basePackage){
        //扫描所有类路径
        URL url = this.getClass().getClassLoader().getResource("/" + basePackage.replaceAll("\\.", "/"));
        String fileStr = url.getFile(); //com.wengen
        File file = new File(fileStr);
        String[] filesStr = file.list();
        for (String path : filesStr) {
            File filePath = new File(fileStr + path);//com.wengen.mvc
            if(filePath.isDirectory()){
                doScanClass(basePackage+"."+path);
            }else{
                //找到了.class结尾的类
                classNames.add(basePackage + "." + filePath.getName());//com.wengen.mvc.controller.WengenController.class
            }
        }

    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String uri = req.getRequestURI();//请求路径：wengen-mvc/wengen/getWengen
        String context = req.getContextPath();//拿到 wengen-mvc
        String path = uri.replace(context,"");//把wengen-mvc替换为空 得到具体的请求路径
        Method method = (Method) handerMap.get(path);
        WengenController instance = (WengenController) beans.get("/"+path.split("/")[1]);
        Object[] args = hand(req, resp, method);
        try {
            method.invoke(instance, args);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    //参数
    private static Object[] hand(HttpServletRequest request, HttpServletResponse response,Method method) {
        //拿到当前执行方法有哪些参数
        Class<?>[] paramsClazz = method.getParameterTypes();
        //根据参数个数new一个参数数组，将方法所有参数赋值到args来
        Object[] args = new Object[paramsClazz.length];
        int agrs_i = 0;
        int index = 0;
        for (Class<?> paramClazz : paramsClazz) {
            if (ServletRequest.class.isAssignableFrom(paramClazz)) {
                args[agrs_i++] = request;
            }
            if (ServletResponse.class.isAssignableFrom(paramClazz)) {
                args[agrs_i++] = response;
            }
            Annotation[] paramAns = method.getParameterAnnotations()[index];
            if(paramAns.length>0){
                for (Annotation paramAn : paramAns) {
                    if (WenRequestParam.class.isAssignableFrom(paramAn.getClass())) {
                        WenRequestParam rp = (WenRequestParam) paramAn;
                        args[agrs_i++] = request.getParameter(rp.value());
                    }
                }
            }
            index++;
        }
        return args;
    }

}
